home *** CD-ROM | disk | FTP | other *** search
/ MacWorld 2003 August / MW 8 2003 CD1.iso / Inside Macworld / Product News / gimp-1.2.4.sit / gimp-1.2.4 / plug-ins / script-fu / script-fu-scripts.c < prev    next >
Encoding:
C/C++ Source or Header  |  2002-03-31  |  61.9 KB  |  2,228 lines

  1. /* The GIMP -- an image manipulation program
  2.  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
  3.  *
  4.  * This program is free software; you can redistribute it and/or modify
  5.  * it under the terms of the GNU General Public License as published by
  6.  * the Free Software Foundation; either version 2 of the License, or
  7.  * (at your option) any later version.
  8.  *
  9.  * This program is distributed in the hope that it will be useful,
  10.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.  * GNU General Public License for more details.
  13.  *
  14.  * You should have received a copy of the GNU General Public License
  15.  * along with this program; if not, write to the Free Software
  16.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  17.  */
  18.  
  19. #include "config.h"
  20.  
  21. #include <glib.h>        /* Include early for obscure Win32
  22.                    build reasons */
  23. #include <stdlib.h>
  24. #include <stdio.h>
  25. #include <string.h>
  26. #include <sys/types.h>
  27. #if HAVE_DIRENT_H
  28. #include <dirent.h>
  29. #endif
  30. #include <sys/stat.h>
  31. #include <ctype.h>        /* For toupper() */
  32.  
  33. #include <gtk/gtk.h>
  34.  
  35. #include <libgimp/gimp.h>
  36. #include <libgimp/gimpui.h>
  37.  
  38. #include "siod.h"
  39. #include "script-fu-scripts.h"
  40.  
  41. #include "script-fu-intl.h"
  42.  
  43. #ifdef G_OS_WIN32
  44. #define STRICT
  45. #include <windows.h>
  46.  
  47. #include <io.h>
  48.  
  49. #ifndef W_OK
  50. #define W_OK 2
  51. #endif
  52. #ifndef S_ISDIR
  53. #define S_ISDIR(m) ((m) & _S_IFDIR)
  54. #endif
  55. #ifndef S_ISREG
  56. #define S_ISREG(m) ((m) & _S_IFREG)
  57. #endif
  58.  
  59. #endif /* G_OS_WIN32 */
  60.  
  61. #define ESCAPE(string) gimp_strescape (string, NULL)
  62.  
  63. #define TEXT_WIDTH           100
  64. #define TEXT_HEIGHT           25
  65. #define COLOR_SAMPLE_WIDTH   100
  66. #define COLOR_SAMPLE_HEIGHT   15
  67. #define SLIDER_WIDTH         100
  68. #define SPINNER_WIDTH         75
  69. #define FONT_PREVIEW_WIDTH   100
  70.  
  71. #define DEFAULT_FONT_SIZE    240
  72.  
  73. #define MAX_STRING_LENGTH   4096
  74.  
  75.  
  76. typedef struct
  77. {
  78.   GtkAdjustment    *adj;
  79.   gfloat            value;
  80.   gfloat            lower;
  81.   gfloat            upper;
  82.   gfloat            step;
  83.   gfloat            page;
  84.   gint              digits;
  85.   SFAdjustmentType  type;
  86. } SFAdjustment;
  87.  
  88. typedef struct
  89. {
  90.   GtkWidget *preview;
  91.   GtkWidget *dialog;
  92.   gchar     *fontname;
  93. } SFFont;
  94.  
  95. typedef struct
  96. {
  97.   GtkWidget *fileselection;
  98.   gchar     *filename;
  99. } SFFilename;
  100.  
  101. typedef struct 
  102. {
  103.   gchar   *name;
  104.   gdouble  opacity;
  105.   gint     spacing;
  106.   gint     paint_mode;
  107. } SFBrush;
  108.  
  109. typedef struct 
  110. {
  111.   GSList  *list;
  112.   guint    history;
  113. } SFOption;
  114.  
  115. typedef union
  116. {
  117.   gint32         sfa_image;
  118.   gint32         sfa_drawable;
  119.   gint32         sfa_layer;
  120.   gint32         sfa_channel;
  121.   guchar         sfa_color[3];
  122.   gint32         sfa_toggle;
  123.   gchar         *sfa_value;
  124.   SFAdjustment   sfa_adjustment;
  125.   SFFont         sfa_font;
  126.   SFFilename     sfa_file;
  127.   gchar         *sfa_pattern;
  128.   gchar         *sfa_gradient;
  129.   SFBrush        sfa_brush;
  130.   SFOption       sfa_option;
  131. } SFArgValue;
  132.  
  133. typedef struct
  134. {
  135.   gchar         *script_name;
  136.   gchar         *pdb_name;
  137.   gchar         *description;
  138.   gchar         *help;
  139.   gchar         *author;
  140.   gchar         *copyright;
  141.   gchar         *date;
  142.   gchar         *img_types;
  143.   gint           num_args;
  144.   SFArgType     *arg_types;
  145.   gchar        **arg_labels;
  146.   SFArgValue    *arg_defaults;
  147.   SFArgValue    *arg_values;
  148.   gint32         image_based;
  149.   GimpParamDef  *args;     /*  used only temporary until installed  */
  150. } SFScript;
  151.  
  152. typedef struct
  153. {
  154.   GtkWidget    **args_widgets;
  155.   GtkWidget     *status;
  156.   GtkWidget     *about_dialog;
  157.   gchar         *window_title;
  158.   gchar         *last_command;
  159.   gint           command_count;
  160.   gint           consec_command_count;
  161. } SFInterface;
  162.  
  163.  
  164. /* External functions
  165.  */
  166. extern long  nlength (LISP obj);
  167.  
  168. /*
  169.  *  Local Functions
  170.  */
  171.  
  172. static gint       script_fu_install_script   (gpointer    foo,
  173.                           SFScript   *script,
  174.                           gpointer    bar);
  175. static gint       script_fu_remove_script    (gpointer    foo,
  176.                           SFScript   *script,
  177.                           gpointer    bar);
  178. static void       script_fu_script_proc      (gchar      *name,
  179.                           gint        nparams,
  180.                           GimpParam  *params,
  181.                           gint       *nreturn_vals,
  182.                           GimpParam **return_vals);
  183.  
  184. static SFScript * script_fu_find_script      (gchar      *script_name);
  185. static void       script_fu_free_script      (SFScript   *script);
  186. static void       script_fu_interface        (SFScript   *script);
  187. static void       script_fu_interface_quit   (SFScript   *script);
  188. static void       script_fu_error_msg        (gchar      *command);
  189.  
  190. static void       script_fu_ok_callback             (GtkWidget *widget,
  191.                              gpointer   data);
  192. static void       script_fu_about_callback          (GtkWidget *widget,
  193.                              gpointer   data);
  194. static void       script_fu_reset_callback          (GtkWidget *widget,
  195.                              gpointer   data);
  196. static void       script_fu_menu_callback           (gint32     id,
  197.                              gpointer   data);
  198.  
  199. static void       script_fu_file_selection_callback (GtkWidget *widget,
  200.                              gpointer   data);
  201.  
  202. static void       script_fu_font_preview_callback   (GtkWidget *widget,
  203.                              gpointer   data);
  204.  
  205. static void       script_fu_font_dialog_ok          (GtkWidget *widget,
  206.                              gpointer   data);
  207. static void       script_fu_font_dialog_cancel      (GtkWidget *widget,
  208.                              gpointer   data);
  209. static gint       script_fu_font_dialog_delete      (GtkWidget *widget,
  210.                              GdkEvent  *event,
  211.                              gpointer   data);
  212.  
  213. static void       script_fu_font_preview            (GtkWidget *preview,
  214.                              gchar     *fontname);
  215. static void       script_fu_pattern_preview         (gchar     *name,
  216.                              gint       width,
  217.                              gint       height,
  218.                              gint       bytes,
  219.                              gchar     *mask_data,
  220.                              gint       closing,
  221.                              gpointer   data);
  222. static void       script_fu_gradient_preview        (gchar     *name,
  223.                              gint       width,
  224.                              gdouble   *mask_data,
  225.                              gint       closing,
  226.                              gpointer   data);
  227. static void       script_fu_brush_preview           (gchar     *name,
  228.                              gdouble    opacity,
  229.                              gint       spacing,
  230.                              gint       paint_mode,
  231.                              gint       width,
  232.                              gint       height,
  233.                              gchar     *mask_data,
  234.                              gint       closing,
  235.                              gpointer   data);
  236.  
  237.  
  238. /*
  239.  *  Local variables
  240.  */
  241.  
  242. static struct stat  filestat;
  243. static GTree       *script_list = NULL;
  244. static SFInterface *sf_interface = NULL;  /*  there can only be at most one
  245.                           interactive interface  */
  246.                           
  247. extern gchar        siod_err_msg[];
  248.  
  249. /*
  250.  *  Function definitions
  251.  */
  252.  
  253. void
  254. script_fu_find_scripts (void)
  255. {
  256.   GList *path_list;
  257.   GList *list;
  258.   gchar *path_str;
  259.   gchar *path;
  260.   gchar *filename;
  261.   gchar *command;
  262.   gint   my_err;
  263.   DIR   *dir;
  264.   struct dirent *dir_ent;
  265.  
  266.   /*  Make sure to clear any existing scripts  */
  267.   if (script_list != NULL)
  268.     {
  269.       g_tree_traverse (script_list, 
  270.                (GTraverseFunc)script_fu_remove_script, 
  271.                G_IN_ORDER, 
  272.                NULL);
  273.       g_tree_destroy (script_list);
  274.     }
  275.  
  276. #ifdef ENABLE_NLS
  277.   script_list = g_tree_new ((GCompareFunc)strcoll);
  278. #else
  279.   script_list = g_tree_new ((GCompareFunc)strcmp);
  280. #endif
  281.  
  282.   path_str = gimp_gimprc_query ("script-fu-path");
  283.  
  284.   if (path_str == NULL)
  285.     return;
  286.  
  287.   /* Search through all directories in script-fu-path */
  288.   
  289.   path_list = gimp_path_parse (path_str, 16, TRUE, NULL);
  290.  
  291.   list = path_list;
  292.   while (list)
  293.     {
  294.       path = list->data;
  295.       list = list->next;
  296.  
  297.       /* Open directory */
  298.       dir = opendir (path);
  299.       
  300.       if (!dir)
  301.     g_message ("error reading script directory \"%s\"", path);
  302.       else
  303.     {
  304.       while ((dir_ent = readdir (dir)))
  305.         {
  306.           filename = g_strdup_printf ("%s%s", path, dir_ent->d_name);
  307.           
  308.           if (g_strcasecmp (filename + strlen (filename) - 4, ".scm") == 0)
  309.         {
  310.           /* Check the file and see that it is not a sub-directory */
  311.           my_err = stat (filename, &filestat);
  312.           
  313.           if (!my_err && S_ISREG (filestat.st_mode))
  314.             {
  315.               gchar *qf = ESCAPE (filename);
  316. #ifdef __EMX__
  317.               _fnslashify(qf);
  318. #endif
  319.               command = g_strdup_printf ("(load \"%s\")", qf);
  320.               g_free (qf);
  321.               
  322.               if (repl_c_string (command, 0, 0, 1) != 0)
  323.             script_fu_error_msg (command);
  324. #ifdef G_OS_WIN32
  325.               /* No, I don't know why, but this is 
  326.                * necessary on NT 4.0.
  327.                */
  328.               Sleep(0);
  329. #endif
  330.               g_free (command);
  331.             }
  332.         }
  333.           
  334.           g_free (filename);
  335.         } /* while */
  336.       
  337.       closedir (dir);
  338.     } /* else */
  339.     } /* while */
  340.   
  341.   g_free (path_str);
  342.  
  343.   /*  now that all scripts are read in and sorted, tell gimp about them  */
  344.   g_tree_traverse (script_list, 
  345.            (GTraverseFunc)script_fu_install_script, G_IN_ORDER, NULL);
  346. }
  347.  
  348. LISP
  349. script_fu_add_script (LISP a)
  350. {
  351.   GimpParamDef *args;
  352.   SFScript     *script;
  353.   gchar        *val;
  354.   gint          i;
  355.   guchar        color[3];
  356.   LISP          color_list;
  357.   LISP          adj_list;
  358.   LISP          brush_list;
  359.   LISP          option_list;
  360.   gchar        *s;
  361.  
  362.   /*  Check the length of a  */
  363.   if (nlength (a) < 7)
  364.     return my_err ("Too few arguments to script-fu-register", NIL);
  365.  
  366.   /*  Create a new script  */
  367.   script = g_new0 (SFScript, 1);
  368.  
  369.   /*  Find the script name  */
  370.   val = get_c_string (car (a));
  371.   script->script_name = g_strdup (val);
  372.   a = cdr (a);
  373.  
  374.   /* transform the function name into a name containing "_" for each "-".
  375.    * this does not hurt anybody, yet improves the life of many... ;)
  376.    */
  377.   script->pdb_name = g_strdup (val);
  378.  
  379.   for (s = script->pdb_name; *s; s++)
  380.     if (*s == '-')
  381.       *s = '_';
  382.  
  383.   /*  Find the script description  */
  384.   val = get_c_string (car (a));
  385.   script->description = g_strdup (val);
  386.   a = cdr (a);
  387.  
  388.   /*  Find the script help  */
  389.   val = get_c_string (car (a));
  390.   script->help = g_strdup (val);
  391.   a = cdr (a);
  392.  
  393.   /*  Find the script author  */
  394.   val = get_c_string (car (a));
  395.   script->author = g_strdup (val);
  396.   a = cdr (a);
  397.  
  398.   /*  Find the script copyright  */
  399.   val = get_c_string (car (a));
  400.   script->copyright = g_strdup (val);
  401.   a = cdr (a);
  402.  
  403.   /*  Find the script date  */
  404.   val = get_c_string (car (a));
  405.   script->date = g_strdup (val);
  406.   a = cdr (a);
  407.  
  408.   /*  Find the script image types  */
  409.   if (TYPEP (a, tc_cons))
  410.     {
  411.       val = get_c_string (car (a));
  412.       a = cdr (a);
  413.     }
  414.   else
  415.     {
  416.       val = get_c_string (a);
  417.       a = NIL;
  418.     }
  419.   script->img_types = g_strdup (val);
  420.  
  421.   /*  Check the supplied number of arguments  */
  422.   script->num_args = nlength (a) / 3;
  423.  
  424.   args = g_new (GimpParamDef, script->num_args + 1);
  425.   args[0].type = GIMP_PDB_INT32;
  426.   args[0].name = "run_mode";
  427.   args[0].description = "Interactive, non-interactive";
  428.  
  429.   script->arg_types    = g_new (SFArgType, script->num_args);
  430.   script->arg_labels   = g_new (gchar *, script->num_args);
  431.   script->arg_defaults = g_new0 (SFArgValue, script->num_args);
  432.   script->arg_values   = g_new0 (SFArgValue, script->num_args);
  433.  
  434.   if (script->num_args > 0)
  435.     {
  436.       for (i = 0; i < script->num_args; i++)
  437.     {
  438.       if (a != NIL)
  439.         {
  440.           if (!TYPEP (car (a), tc_flonum))
  441.         return my_err ("script-fu-register: argument types must be integer values", NIL);
  442.           script->arg_types[i] = get_c_long (car (a));
  443.           a = cdr (a);
  444.         }
  445.       else
  446.         return my_err ("script-fu-register: missing type specifier", NIL);
  447.  
  448.       if (a != NIL)
  449.         {
  450.           if (!TYPEP (car (a), tc_string))
  451.         return my_err ("script-fu-register: argument labels must be strings", NIL);
  452.           script->arg_labels[i] = g_strdup (get_c_string (car (a)));
  453.           a = cdr (a);
  454.         }
  455.       else
  456.         return my_err ("script-fu-register: missing arguments label", NIL);
  457.  
  458.       if (a != NIL)
  459.         {
  460.           switch (script->arg_types[i])
  461.         {
  462.         case SF_IMAGE:
  463.         case SF_DRAWABLE:
  464.         case SF_LAYER:
  465.         case SF_CHANNEL:
  466.           if (!TYPEP (car (a), tc_flonum))
  467.             return my_err ("script-fu-register: drawable defaults must be integer values", NIL);
  468.           script->arg_defaults[i].sfa_image = get_c_long (car (a));
  469.           script->arg_values[i].sfa_image = script->arg_defaults[i].sfa_image;
  470.  
  471.           switch (script->arg_types[i])
  472.             {
  473.             case SF_IMAGE:
  474.               args[i + 1].type = GIMP_PDB_IMAGE;
  475.               args[i + 1].name = "image";
  476.               break;
  477.  
  478.             case SF_DRAWABLE:
  479.               args[i + 1].type = GIMP_PDB_DRAWABLE;
  480.               args[i + 1].name = "drawable";
  481.               break;
  482.  
  483.             case SF_LAYER:
  484.               args[i + 1].type = GIMP_PDB_LAYER;
  485.               args[i + 1].name = "layer";
  486.               break;
  487.  
  488.             case SF_CHANNEL:
  489.               args[i + 1].type = GIMP_PDB_CHANNEL;
  490.               args[i + 1].name = "channel";
  491.               break;
  492.  
  493.             default:
  494.               break;
  495.             }
  496.  
  497.           args[i + 1].description = script->arg_labels[i];
  498.           break;
  499.  
  500.         case SF_COLOR:
  501.           if (!TYPEP (car (a), tc_cons))
  502.             return my_err ("script-fu-register: color defaults must be a list of 3 integers", NIL);
  503.           color_list = car (a);
  504.           color[0] = 
  505.             (guchar)(CLAMP (get_c_long (car (color_list)), 0, 255));
  506.           color_list = cdr (color_list);
  507.           color[1] = 
  508.             (guchar)(CLAMP (get_c_long (car (color_list)), 0, 255));
  509.           color_list = cdr (color_list);
  510.           color[2] = 
  511.             (guchar)(CLAMP (get_c_long (car (color_list)), 0, 255));
  512.           memcpy (script->arg_defaults[i].sfa_color, 
  513.               color, sizeof (guchar) * 3);
  514.           memcpy (script->arg_values[i].sfa_color, 
  515.               color, sizeof (guchar) * 3);
  516.  
  517.           args[i + 1].type = GIMP_PDB_COLOR;
  518.           args[i + 1].name = "color";
  519.           args[i + 1].description = script->arg_labels[i];
  520.           break;
  521.  
  522.         case SF_TOGGLE:
  523.           if (!TYPEP (car (a), tc_flonum))
  524.             return my_err ("script-fu-register: toggle default must be an integer value", NIL);
  525.           script->arg_defaults[i].sfa_toggle = 
  526.             (get_c_long (car (a))) ? TRUE : FALSE;
  527.           script->arg_values[i].sfa_toggle = 
  528.             script->arg_defaults[i].sfa_toggle;
  529.  
  530.           args[i + 1].type = GIMP_PDB_INT32;
  531.           args[i + 1].name = "toggle";
  532.           args[i + 1].description = script->arg_labels[i];
  533.           break;
  534.  
  535.         case SF_VALUE:  
  536.           if (!TYPEP (car (a), tc_string))
  537.             return my_err ("script-fu-register: value defaults must be string values", NIL);
  538.           script->arg_defaults[i].sfa_value = 
  539.             g_strdup (get_c_string (car (a)));
  540.           script->arg_values[i].sfa_value =  
  541.             g_strdup (script->arg_defaults[i].sfa_value);
  542.  
  543.           args[i + 1].type = GIMP_PDB_STRING;
  544.           args[i + 1].name = "value";
  545.           args[i + 1].description = script->arg_labels[i];
  546.           break;
  547.  
  548.         case SF_STRING:
  549.           if (!TYPEP (car (a), tc_string))
  550.             return my_err ("script-fu-register: string defaults must be string values", NIL);
  551.           script->arg_defaults[i].sfa_value = 
  552.             g_strdup (get_c_string (car (a)));
  553.           script->arg_values[i].sfa_value =  
  554.             g_strdup (script->arg_defaults[i].sfa_value);
  555.  
  556.           args[i + 1].type = GIMP_PDB_STRING;
  557.           args[i + 1].name = "string";
  558.           args[i + 1].description = script->arg_labels[i];
  559.           break;
  560.  
  561.         case SF_ADJUSTMENT:
  562.           if (!TYPEP (car (a), tc_cons))
  563.             return my_err ("script-fu-register: adjustment defaults must be a list", NIL);
  564.           adj_list = car (a);
  565.           script->arg_defaults[i].sfa_adjustment.value = 
  566.             get_c_double (car (adj_list));
  567.           adj_list = cdr (adj_list);
  568.           script->arg_defaults[i].sfa_adjustment.lower = 
  569.             get_c_double (car (adj_list));
  570.           adj_list = cdr (adj_list);
  571.           script->arg_defaults[i].sfa_adjustment.upper = 
  572.             get_c_double (car (adj_list));
  573.           adj_list = cdr (adj_list);
  574.           script->arg_defaults[i].sfa_adjustment.step = 
  575.             get_c_double (car (adj_list));
  576.           adj_list = cdr (adj_list);
  577.           script->arg_defaults[i].sfa_adjustment.page = 
  578.             get_c_double (car (adj_list));
  579.           adj_list = cdr (adj_list);
  580.           script->arg_defaults[i].sfa_adjustment.digits = 
  581.             get_c_long (car (adj_list));
  582.           adj_list = cdr (adj_list);
  583.           script->arg_defaults[i].sfa_adjustment.type = 
  584.             get_c_long (car (adj_list));
  585.           script->arg_values[i].sfa_adjustment.adj = NULL;
  586.           script->arg_values[i].sfa_adjustment.value = 
  587.             script->arg_defaults[i].sfa_adjustment.value;
  588.  
  589.           args[i + 1].type = GIMP_PDB_STRING;
  590.           args[i + 1].name = "value";
  591.           args[i + 1].description = script->arg_labels[i];
  592.           break;
  593.  
  594.         case SF_FILENAME:
  595.           if (!TYPEP (car (a), tc_string))
  596.             return my_err ("script-fu-register: filename defaults must be string values", NIL);
  597.           script->arg_defaults[i].sfa_file.filename = 
  598.             g_strdup (get_c_string (car (a)));
  599.  
  600. #ifdef G_OS_WIN32
  601.           /* Replace POSIX slashes with Win32 backslashes. This
  602.            * is just so script-fus can be written with only
  603.            * POSIX directory separators.
  604.            */
  605.           val = script->arg_defaults[i].sfa_file.filename;
  606.           while (*val)
  607.             {
  608.               if (*val == '/')
  609.             *val = '\\';
  610.               val++;
  611.             }
  612. #endif
  613.           script->arg_values[i].sfa_file.filename =  
  614.             g_strdup (script->arg_defaults[i].sfa_file.filename);
  615.           script->arg_values[i].sfa_file.fileselection = NULL;
  616.  
  617.           args[i + 1].type = GIMP_PDB_STRING;
  618.           args[i + 1].name = "filename";
  619.           args[i + 1].description = script->arg_labels[i];
  620.          break;
  621.  
  622.         case SF_FONT:
  623.           if (!TYPEP (car (a), tc_string))
  624.             return my_err ("script-fu-register: font defaults must be string values", NIL);
  625.           script->arg_defaults[i].sfa_font.fontname = 
  626.             g_strdup (get_c_string (car (a)));
  627.           script->arg_values[i].sfa_font.fontname =  
  628.             g_strdup (script->arg_defaults[i].sfa_font.fontname);
  629.           script->arg_values[i].sfa_font.preview = NULL;
  630.           script->arg_values[i].sfa_font.dialog = NULL;
  631.           
  632.           args[i + 1].type = GIMP_PDB_STRING;
  633.           args[i + 1].name = "font";
  634.           args[i + 1].description = script->arg_labels[i];
  635.           break;
  636.  
  637.         case SF_PATTERN:
  638.           if (!TYPEP (car (a), tc_string))
  639.             return my_err ("script-fu-register: pattern defaults must be string values", NIL);
  640.           script->arg_defaults[i].sfa_pattern = 
  641.             g_strdup (get_c_string (car (a)));
  642.           script->arg_values[i].sfa_pattern =  
  643.             g_strdup (script->arg_defaults[i].sfa_pattern);
  644.  
  645.           args[i + 1].type = GIMP_PDB_STRING;
  646.           args[i + 1].name = "pattern";
  647.           args[i + 1].description = script->arg_labels[i];
  648.           break;
  649.  
  650.         case SF_BRUSH:
  651.           if (!TYPEP (car (a), tc_cons))
  652.             return my_err ("script-fu-register: brush defaults must be a list", NIL);
  653.           brush_list = car (a);
  654.           script->arg_defaults[i].sfa_brush.name = 
  655.             g_strdup (get_c_string (car (brush_list)));
  656.           brush_list = cdr (brush_list);
  657.           script->arg_defaults[i].sfa_brush.opacity = 
  658.             get_c_double (car (brush_list));
  659.           brush_list = cdr (brush_list);
  660.           script->arg_defaults[i].sfa_brush.spacing = 
  661.             get_c_long (car (brush_list));
  662.           brush_list = cdr (brush_list);
  663.           script->arg_defaults[i].sfa_brush.paint_mode = 
  664.             get_c_long (car (brush_list));
  665.           script->arg_values[i].sfa_brush = 
  666.             script->arg_defaults[i].sfa_brush;
  667.           /* Need this since we need a copy of the string
  668.            * in the values area. We could free it later but the
  669.            * default one must hang around.
  670.            */
  671.           script->arg_values[i].sfa_brush.name = 
  672.             g_strdup(script->arg_defaults[i].sfa_brush.name);
  673.  
  674.           args[i + 1].type = GIMP_PDB_STRING;
  675.           args[i + 1].name = "brush";
  676.           args[i + 1].description = script->arg_labels[i];
  677.           break;
  678.  
  679.         case SF_GRADIENT:
  680.           if (!TYPEP (car (a), tc_string))
  681.             return my_err ("script-fu-register: gradient defaults must be string values", NIL);
  682.           script->arg_defaults[i].sfa_gradient = 
  683.             g_strdup (get_c_string (car (a)));
  684.           script->arg_values[i].sfa_gradient =  
  685.             g_strdup (script->arg_defaults[i].sfa_pattern);
  686.           
  687.           args[i + 1].type = GIMP_PDB_STRING;
  688.           args[i + 1].name = "gradient";
  689.           args[i + 1].description = script->arg_labels[i];
  690.           break;
  691.  
  692.         case SF_OPTION:
  693.           if (!TYPEP (car (a), tc_cons))
  694.             return my_err ("script-fu-register: option defaults must be a list", NIL);
  695.           for (option_list = car (a); 
  696.                option_list; 
  697.                option_list = cdr (option_list))
  698.             {
  699.               script->arg_defaults[i].sfa_option.list = 
  700.             g_slist_append (script->arg_defaults[i].sfa_option.list, 
  701.                     g_strdup (get_c_string (car (option_list))));
  702.             }
  703.           script->arg_defaults[i].sfa_option.history = 0;
  704.           script->arg_values[i].sfa_option.history = 0;
  705.  
  706.           args[i + 1].type = GIMP_PDB_INT32;
  707.           args[i + 1].name = "option";
  708.           args[i + 1].description = script->arg_labels[i];
  709.           break;
  710.  
  711.         default:
  712.           break;
  713.         }
  714.  
  715.           a = cdr (a);
  716.         }
  717.       else
  718.         return my_err ("script-fu-register: missing default argument", NIL);
  719.     }
  720.     }
  721.  
  722.   script->args = args;
  723.   g_tree_insert (script_list, gettext (script->description), script);
  724.  
  725.   return NIL;
  726. }
  727.  
  728. void
  729. script_fu_report_cc (gchar *command)
  730. {
  731.   if (sf_interface == NULL)
  732.     return;
  733.  
  734.   if (sf_interface->last_command && 
  735.       strcmp (sf_interface->last_command, command) == 0)
  736.     {
  737.       gchar *new_command;
  738.  
  739.       sf_interface->command_count++;
  740.  
  741.       new_command = g_strdup_printf ("%s <%d>", 
  742.                      command, sf_interface->command_count);
  743.       gtk_entry_set_text (GTK_ENTRY (sf_interface->status), new_command);
  744.       g_free (new_command);
  745.     }
  746.   else
  747.     {
  748.       sf_interface->command_count = 1;
  749.       gtk_entry_set_text (GTK_ENTRY (sf_interface->status), command);
  750.       g_free (sf_interface->last_command);
  751.       sf_interface->last_command = g_strdup (command);
  752.     }
  753.   
  754.   gdk_flush ();
  755. }
  756.  
  757.  
  758. /* 
  759.  *  The following function is a GTraverseFunction, Please 
  760.  *  note that it frees the script->args structure.  --Sven 
  761.  */
  762. static gint
  763. script_fu_install_script (gpointer  foo,
  764.               SFScript *script,
  765.               gpointer  bar)
  766. {
  767.   gchar *menu_path = NULL;
  768.  
  769.   /* Allow scripts with no menus */
  770.   if (strncmp (script->description, "<None>", 6) != 0)
  771.     menu_path = script->description;
  772.  
  773.   gimp_install_temp_proc (script->pdb_name,
  774.                           script->description,
  775.                           script->help,
  776.                           script->author,
  777.                           script->copyright,
  778.                           script->date,
  779.                           menu_path,
  780.                           script->img_types,
  781.                           GIMP_TEMPORARY,
  782.                           script->num_args + 1, 0,
  783.                           script->args, NULL,
  784.                           script_fu_script_proc);
  785.  
  786.   g_free (script->args);
  787.   script->args = NULL;
  788.  
  789.   return FALSE;
  790. }
  791.  
  792. /* 
  793.  *  The following function is a GTraverseFunction.
  794.  */
  795. static gint
  796. script_fu_remove_script (gpointer  foo,
  797.              SFScript *script,
  798.              gpointer  bar)
  799. {
  800.   script_fu_free_script (script);
  801.  
  802.   return FALSE;
  803. }
  804.  
  805.  
  806.  
  807. static void
  808. script_fu_script_proc (gchar       *name,
  809.                gint         nparams,
  810.                GimpParam   *params,
  811.                gint        *nreturn_vals,
  812.                GimpParam  **return_vals)
  813. {
  814.   static GimpParam  values[1];
  815.   GimpPDBStatusType status = GIMP_PDB_SUCCESS;
  816.   GimpRunModeType   run_mode;
  817.   SFScript         *script;
  818.   gint              min_args;
  819.   gchar            *escaped;
  820.  
  821.   run_mode = params[0].data.d_int32;
  822.  
  823.   if (! (script = script_fu_find_script (name)))
  824.     status = GIMP_PDB_CALLING_ERROR;
  825.   else
  826.     {
  827.       if (script->num_args == 0)
  828.     run_mode = GIMP_RUN_NONINTERACTIVE;
  829.  
  830.       switch (run_mode)
  831.     {
  832.     case GIMP_RUN_INTERACTIVE:
  833.     case GIMP_RUN_WITH_LAST_VALS:
  834.       /*  Determine whether the script is image based (runs on an image) */
  835.       if (strncmp (script->description, "<Image>", 7) == 0)
  836.         {
  837.           script->arg_values[0].sfa_image    = params[1].data.d_image;
  838.           script->arg_values[1].sfa_drawable = params[2].data.d_drawable;
  839.           script->image_based = TRUE;
  840.         }
  841.       else
  842.         script->image_based = FALSE;
  843.  
  844.       /*  First acquire information with a dialog  */
  845.       /*  Skip this part if the script takes no parameters */ 
  846.       min_args = (script->image_based) ? 2 : 0;
  847.       if (script->num_args > min_args) 
  848.         {
  849.           script_fu_interface (script); 
  850.           break;
  851.         }  
  852.       /*  else fallthrough  */
  853.  
  854.     case GIMP_RUN_NONINTERACTIVE:
  855.       /*  Make sure all the arguments are there!  */
  856.       if (nparams != (script->num_args + 1))
  857.         status = GIMP_PDB_CALLING_ERROR;
  858.       if (status == GIMP_PDB_SUCCESS)
  859.         {
  860.           gchar *text = NULL;
  861.           gchar *command;
  862.           gchar *c;
  863.           gchar  buffer[MAX_STRING_LENGTH];
  864.           gint   length;
  865.           gint   i;
  866.  
  867.           length = strlen (script->script_name) + 3;
  868.  
  869.           for (i = 0; i < script->num_args; i++)
  870.         switch (script->arg_types[i])
  871.           {
  872.           case SF_IMAGE:
  873.           case SF_DRAWABLE:
  874.           case SF_LAYER:
  875.           case SF_CHANNEL:
  876.             length += 12;  /*  Maximum size of integer value will not exceed this many characters  */
  877.             break;
  878.  
  879.           case SF_COLOR:
  880.             length += 16;  /*  Maximum size of color string: '(XXX XXX XXX)  */
  881.             break;
  882.  
  883.           case SF_TOGGLE:
  884.             length += 6;   /*  Maximum size of (TRUE, FALSE)  */
  885.             break;
  886.  
  887.           case SF_VALUE:
  888.             length += strlen (params[i + 1].data.d_string) + 1;
  889.             break;
  890.  
  891.           case SF_STRING:
  892.           case SF_FILENAME:
  893.             escaped = ESCAPE (params[i + 1].data.d_string);
  894.             length += strlen (escaped) + 3;
  895.             g_free (escaped);
  896.             break;
  897.  
  898.           case SF_ADJUSTMENT:
  899.             length += strlen (params[i + 1].data.d_string) + 1;
  900.             break;
  901.  
  902.           case SF_FONT:
  903.           case SF_PATTERN:
  904.           case SF_GRADIENT:
  905.           case SF_BRUSH:
  906.             length += strlen (params[i + 1].data.d_string) + 3;
  907.             break;            
  908.  
  909.           case SF_OPTION:
  910.             length += strlen (params[i + 1].data.d_string) + 1;
  911.             break;
  912.  
  913.           default:
  914.             break;
  915.           }
  916.  
  917.           c = command = g_new (gchar, length);
  918.  
  919.           if (script->num_args)
  920.                 {
  921.                   sprintf (command, "(%s ", script->script_name);
  922.                   c += strlen (script->script_name) + 2;
  923.  
  924.                   for (i = 0; i < script->num_args; i++)
  925.                     {
  926.                       switch (script->arg_types[i])
  927.                         {
  928.                         case SF_IMAGE:
  929.                         case SF_DRAWABLE:
  930.                         case SF_LAYER:
  931.                         case SF_CHANNEL:
  932.                           g_snprintf (buffer, sizeof (buffer), "%d",
  933.                       params[i + 1].data.d_image);
  934.                           text = buffer;
  935.                           break;
  936.  
  937.                         case SF_COLOR:
  938.                           g_snprintf (buffer, sizeof (buffer), "'(%d %d %d)",
  939.                       params[i + 1].data.d_color.red,
  940.                       params[i + 1].data.d_color.green,
  941.                       params[i + 1].data.d_color.blue);
  942.                           text = buffer;
  943.                           break;
  944.  
  945.                         case SF_TOGGLE:
  946.                           g_snprintf (buffer, sizeof (buffer), "%s",
  947.                       (params[i + 1].data.d_int32) ? "TRUE" 
  948.                                                    : "FALSE");
  949.                           text = buffer;
  950.                           break;
  951.  
  952.                         case SF_VALUE:
  953.                           text = params[i + 1].data.d_string;
  954.                           break;
  955.  
  956.                         case SF_STRING:
  957.                         case SF_FILENAME:
  958.                           escaped = ESCAPE (params[i + 1].data.d_string);
  959.                           g_snprintf (buffer, sizeof (buffer), "\"%s\"",
  960.                       escaped);
  961.                           g_free (escaped);
  962.                           text = buffer;
  963.                           break;
  964.  
  965.                         case SF_ADJUSTMENT:
  966.                           text = params[i + 1].data.d_string;
  967.                           break;
  968.  
  969.                         case SF_FONT:
  970.                         case SF_PATTERN:
  971.                         case SF_GRADIENT:
  972.                         case SF_BRUSH:
  973.                           g_snprintf (buffer, sizeof (buffer), "\"%s\"",
  974.                       params[i + 1].data.d_string);
  975.                           text = buffer;
  976.                           break;
  977.  
  978.                         case SF_OPTION:
  979.                           text = params[i + 1].data.d_string;
  980.                           break;
  981.  
  982.                         default:
  983.                           break;
  984.                         }
  985.  
  986.                       if (i == script->num_args - 1)
  987.                         sprintf (c, "%s)", text);
  988.                       else
  989.                         sprintf (c, "%s ", text);
  990.  
  991.                       c += strlen (text) + 1;
  992.                     }
  993.                 }
  994.           else
  995.         sprintf (command, "(%s)", script->script_name);
  996.  
  997.           /*  run the command through the interpreter  */
  998.           if (repl_c_string (command, 0, 0, 1) != 0)
  999.         script_fu_error_msg (command);
  1000.      
  1001.           g_free (command);
  1002.         }
  1003.       break;
  1004.  
  1005.     default:
  1006.       break;
  1007.     }
  1008.     }
  1009.  
  1010.   *nreturn_vals = 1;
  1011.   *return_vals = values;
  1012.  
  1013.   values[0].type = GIMP_PDB_STATUS;
  1014.   values[0].data.d_status = status;
  1015. }
  1016.  
  1017. /* this is a GTraverseFunction */
  1018. static gint
  1019. script_fu_lookup_script (gpointer  *foo,
  1020.              SFScript  *script,
  1021.              gchar    **name)
  1022. {
  1023.   if (strcmp (script->pdb_name, *name) == 0)
  1024.     {  
  1025.       /* store the script in the name pointer and stop the traversal */
  1026.       *name = (gchar *)script;
  1027.       return TRUE;
  1028.     }
  1029.   else
  1030.     return FALSE;
  1031. }
  1032.  
  1033. static SFScript *
  1034. script_fu_find_script (gchar *pdb_name)
  1035. {
  1036.   gchar *script;
  1037.   
  1038.   script = pdb_name;
  1039.   g_tree_traverse (script_list, 
  1040.            (GTraverseFunc)script_fu_lookup_script, G_IN_ORDER, &script);
  1041.   if (script == pdb_name)
  1042.     return NULL;
  1043.   else
  1044.     return (SFScript *)script;
  1045. }
  1046.  
  1047. static void
  1048. script_fu_free_script (SFScript *script)
  1049. {
  1050.   gint i;
  1051.  
  1052.   /*  Uninstall the temporary procedure for this script  */
  1053.   gimp_uninstall_temp_proc (script->script_name);
  1054.  
  1055.   if (script)
  1056.     {
  1057.       g_free (script->script_name);
  1058.       g_free (script->description);
  1059.       g_free (script->help);
  1060.       g_free (script->author);
  1061.       g_free (script->copyright);
  1062.       g_free (script->date);
  1063.       g_free (script->img_types);
  1064.       g_free (script->arg_types);
  1065.  
  1066.       for (i = 0; i < script->num_args; i++)
  1067.     {
  1068.       g_free (script->arg_labels[i]);
  1069.       switch (script->arg_types[i])
  1070.         {
  1071.         case SF_IMAGE:
  1072.         case SF_DRAWABLE:
  1073.         case SF_LAYER:
  1074.         case SF_CHANNEL:
  1075.         case SF_COLOR:
  1076.           break;
  1077.  
  1078.         case SF_VALUE:
  1079.         case SF_STRING:
  1080.           g_free (script->arg_defaults[i].sfa_value);
  1081.           g_free (script->arg_values[i].sfa_value);
  1082.           break;
  1083.  
  1084.         case SF_ADJUSTMENT:
  1085.           break;
  1086.  
  1087.         case SF_FILENAME:
  1088.           g_free (script->arg_defaults[i].sfa_file.filename);
  1089.           g_free (script->arg_values[i].sfa_file.filename);
  1090.           break;
  1091.  
  1092.         case SF_FONT:
  1093.           g_free (script->arg_defaults[i].sfa_font.fontname);
  1094.           g_free (script->arg_values[i].sfa_font.fontname);
  1095.           break;
  1096.  
  1097.         case SF_PATTERN:
  1098.           g_free (script->arg_defaults[i].sfa_pattern);
  1099.           g_free (script->arg_values[i].sfa_pattern);
  1100.           break;
  1101.  
  1102.         case SF_GRADIENT:
  1103.           g_free (script->arg_defaults[i].sfa_gradient);
  1104.           g_free (script->arg_values[i].sfa_gradient);
  1105.           break;
  1106.  
  1107.         case SF_BRUSH:
  1108.           g_free (script->arg_defaults[i].sfa_brush.name);
  1109.           g_free (script->arg_values[i].sfa_brush.name);
  1110.           break;
  1111.  
  1112.         case SF_OPTION:
  1113.           g_slist_foreach (script->arg_defaults[i].sfa_option.list, 
  1114.                    (GFunc)g_free, NULL);
  1115.           if (script->arg_defaults[i].sfa_option.list)
  1116.         g_slist_free (script->arg_defaults[i].sfa_option.list);
  1117.           break;
  1118.  
  1119.         default:
  1120.           break;
  1121.         }
  1122.     }
  1123.  
  1124.       g_free (script->arg_labels);
  1125.       g_free (script->arg_defaults);
  1126.       g_free (script->arg_values);
  1127.  
  1128.       g_free (script);
  1129.     }
  1130. }
  1131.  
  1132. static void
  1133. script_fu_interface (SFScript *script)
  1134. {
  1135.   GtkWidget *dlg;
  1136.   GtkWidget *main_box;
  1137.   GtkWidget *frame;
  1138.   GtkWidget *sep;
  1139.   GtkWidget *button;
  1140.   GtkWidget *menu;
  1141.   GtkWidget *table;
  1142.   GtkWidget *vbox;
  1143.   GtkWidget *hbox;
  1144.   GtkWidget *bbox;
  1145.   GtkWidget *menu_item;
  1146.   GSList    *list;
  1147.   gchar     *buf;
  1148.   gint       start_args;
  1149.   gint       i;
  1150.   guint      j;
  1151.  
  1152.   static gboolean gtk_initted = FALSE;
  1153.  
  1154.   /*  Simply return if there is already an interface. This is an
  1155.       ugly workaround for the fact that we can not process two
  1156.       scripts at a time.  */
  1157.   if (sf_interface != NULL)
  1158.     return;
  1159.  
  1160.   g_return_if_fail (script != NULL);
  1161.  
  1162.   if (!gtk_initted)
  1163.     {
  1164.       INIT_I18N_UI();
  1165.  
  1166.       gimp_ui_init ("script-fu", TRUE);
  1167.  
  1168.       gtk_initted = TRUE;
  1169.     }
  1170.  
  1171.   sf_interface = g_new0 (SFInterface, 1);
  1172.   sf_interface->args_widgets = g_new0 (GtkWidget *, script->num_args);
  1173.   
  1174.   /* strip the first part of the menupath if it contains _("/Script-Fu/") */
  1175.   buf = strstr (gettext (script->description), _("/Script-Fu/"));
  1176.   if (buf)
  1177.     sf_interface->window_title = g_strdup_printf (_("Script-Fu: %s"), 
  1178.                           (buf + strlen (_("/Script-Fu/"))));
  1179.   else 
  1180.     sf_interface->window_title = g_strdup_printf (_("Script-Fu: %s"), 
  1181.                         gettext (script->description));
  1182.  
  1183.   buf = strstr (sf_interface->window_title, "...");
  1184.   if (buf)
  1185.     *buf = '\0';
  1186.  
  1187.   dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL);
  1188.   gtk_quit_add_destroy (1, GTK_OBJECT (dlg));
  1189.   gtk_window_set_title (GTK_WINDOW (dlg), sf_interface->window_title);
  1190.   gtk_window_set_wmclass (GTK_WINDOW (dlg), "script_fu", "Gimp");
  1191.   gtk_signal_connect_object (GTK_OBJECT (dlg), "delete_event",
  1192.                  GTK_SIGNAL_FUNC (script_fu_interface_quit),
  1193.                  (GtkObject *) script);
  1194.                  
  1195.   gimp_help_connect_help_accel (dlg, gimp_standard_help_func,
  1196.                 "filters/script-fu.html");
  1197.   
  1198.   /* the vbox holding all widgets */
  1199.   main_box = gtk_vbox_new (FALSE, 0);
  1200.   gtk_container_add (GTK_CONTAINER (dlg), main_box);
  1201.  
  1202.   /* the script arguments frame */
  1203.   frame = gtk_frame_new (_("Script Arguments"));
  1204.   gtk_container_set_border_width (GTK_CONTAINER (frame), 4);
  1205.   gtk_box_pack_start (GTK_BOX (main_box), frame, TRUE, TRUE, 0);
  1206.  
  1207.   /* the vbox holding all widgets */
  1208.   vbox = gtk_vbox_new (FALSE, 2);
  1209.   gtk_container_add (GTK_CONTAINER (frame), vbox);
  1210.   gtk_container_set_border_width (GTK_CONTAINER (vbox), 2);
  1211.  
  1212.   /*  The argument table  */
  1213.   table = gtk_table_new (script->num_args + 1, 2, FALSE);
  1214.   gtk_table_set_col_spacings (GTK_TABLE (table), 4);
  1215.   gtk_table_set_row_spacings (GTK_TABLE (table), 2);
  1216.   gtk_container_set_border_width (GTK_CONTAINER (table), 4);
  1217.   gtk_box_pack_start (GTK_BOX (vbox), table, TRUE, TRUE, 0);
  1218.  
  1219.   start_args = (script->image_based) ? 2 : 0;
  1220.  
  1221.   for (i = start_args; i < script->num_args; i++)
  1222.     {
  1223.       /*  we add a colon after the label; 
  1224.       some languages want an extra space here */
  1225.       gchar     *label_text = 
  1226.     g_strdup_printf (_("%s:"), gettext (script->arg_labels[i]));
  1227.       gfloat     label_yalign = 0.5;
  1228.       gboolean   widget_leftalign = TRUE;
  1229.  
  1230.       switch (script->arg_types[i])
  1231.     {
  1232.     case SF_IMAGE:
  1233.     case SF_DRAWABLE:
  1234.     case SF_LAYER:
  1235.     case SF_CHANNEL:
  1236.       sf_interface->args_widgets[i] = gtk_option_menu_new ();
  1237.       switch (script->arg_types[i])
  1238.         {
  1239.         case SF_IMAGE:
  1240.           menu = gimp_image_menu_new (NULL, script_fu_menu_callback,
  1241.                       &script->arg_values[i].sfa_image,
  1242.                       script->arg_values[i].sfa_image);
  1243.           break;
  1244.  
  1245.         case SF_DRAWABLE:
  1246.           menu = gimp_drawable_menu_new (NULL, script_fu_menu_callback,
  1247.                          &script->arg_values[i].sfa_drawable,
  1248.                          script->arg_values[i].sfa_drawable);
  1249.           break;
  1250.  
  1251.         case SF_LAYER:
  1252.           menu = gimp_layer_menu_new (NULL, script_fu_menu_callback,
  1253.                       &script->arg_values[i].sfa_layer,
  1254.                       script->arg_values[i].sfa_layer);
  1255.           break;
  1256.  
  1257.         case SF_CHANNEL:
  1258.           menu = gimp_channel_menu_new (NULL, script_fu_menu_callback,
  1259.                         &script->arg_values[i].sfa_channel,
  1260.                         script->arg_values[i].sfa_channel);
  1261.           break;
  1262.  
  1263.         default:
  1264.           menu = NULL;
  1265.           break;
  1266.         }
  1267.       gtk_option_menu_set_menu (GTK_OPTION_MENU (sf_interface->args_widgets[i]),
  1268.                     menu);
  1269.       break;
  1270.  
  1271.     case SF_COLOR:
  1272.       sf_interface->args_widgets[i] =
  1273.         gimp_color_button_new (_("Script-Fu Color Selection"),
  1274.                    COLOR_SAMPLE_WIDTH, COLOR_SAMPLE_HEIGHT,
  1275.                    script->arg_values[i].sfa_color, 3);
  1276.       break;
  1277.  
  1278.     case SF_TOGGLE:
  1279.       g_free (label_text);
  1280.       label_text = NULL;
  1281.       sf_interface->args_widgets[i] =
  1282.         gtk_check_button_new_with_label (gettext (script->arg_labels[i]));
  1283.       gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (sf_interface->args_widgets[i]),
  1284.                        script->arg_values[i].sfa_toggle);
  1285.       gtk_signal_connect (GTK_OBJECT (sf_interface->args_widgets[i]), "toggled",
  1286.                   GTK_SIGNAL_FUNC (gimp_toggle_button_update),
  1287.                   &script->arg_values[i].sfa_toggle);
  1288.       break;
  1289.  
  1290.     case SF_VALUE:
  1291.     case SF_STRING:
  1292.       widget_leftalign = FALSE;
  1293.  
  1294.       sf_interface->args_widgets[i] = gtk_entry_new ();
  1295.       gtk_widget_set_usize (sf_interface->args_widgets[i], TEXT_WIDTH, 0);
  1296.       gtk_entry_set_text (GTK_ENTRY (sf_interface->args_widgets[i]),
  1297.                   script->arg_values[i].sfa_value);
  1298.       break;
  1299.  
  1300.     case SF_ADJUSTMENT:
  1301.       script->arg_values[i].sfa_adjustment.adj = (GtkAdjustment *)
  1302.         gtk_adjustment_new (script->arg_values[i].sfa_adjustment.value, 
  1303.                 script->arg_defaults[i].sfa_adjustment.lower, 
  1304.                 script->arg_defaults[i].sfa_adjustment.upper, 
  1305.                 script->arg_defaults[i].sfa_adjustment.step, 
  1306.                 script->arg_defaults[i].sfa_adjustment.page, 0);
  1307.       switch (script->arg_defaults[i].sfa_adjustment.type)
  1308.         {
  1309.         case SF_SLIDER:
  1310.           label_yalign = 1.0;
  1311.           widget_leftalign = FALSE;
  1312.  
  1313.           sf_interface->args_widgets[i] =
  1314.         gtk_hscale_new (script->arg_values[i].sfa_adjustment.adj);
  1315.           gtk_widget_set_usize (GTK_WIDGET (sf_interface->args_widgets[i]), 
  1316.                     SLIDER_WIDTH, -1);
  1317.           gtk_scale_set_digits (GTK_SCALE (sf_interface->args_widgets[i]), 
  1318.                     script->arg_defaults[i].sfa_adjustment.digits);
  1319.           gtk_scale_set_draw_value (GTK_SCALE (sf_interface->args_widgets[i]), TRUE);
  1320.           gtk_range_set_update_policy (GTK_RANGE (sf_interface->args_widgets[i]), 
  1321.                        GTK_UPDATE_DELAYED);
  1322.           break;
  1323.  
  1324.         case SF_SPINNER:
  1325.           sf_interface->args_widgets[i] =
  1326.         gtk_spin_button_new (script->arg_values[i].sfa_adjustment.adj, 0, 0);
  1327.           gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (sf_interface->args_widgets[i]), TRUE);
  1328.           gtk_widget_set_usize (sf_interface->args_widgets[i], SPINNER_WIDTH, 0);
  1329.           gtk_spin_button_set_digits (GTK_SPIN_BUTTON (sf_interface->args_widgets[i]),
  1330.                       script->arg_defaults[i].sfa_adjustment.digits);
  1331.           gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (sf_interface->args_widgets[i]), TRUE);
  1332.           break;
  1333.         default: /* this shouldn't happen */
  1334.           sf_interface->args_widgets[i] = NULL;
  1335.           break;
  1336.         }
  1337.       break;
  1338.  
  1339.     case SF_FILENAME:
  1340.       widget_leftalign = FALSE
  1341. ;
  1342.       sf_interface->args_widgets[i] =
  1343.         gimp_file_selection_new (_("Script-Fu File Selection"),
  1344.                      script->arg_values[i].sfa_file.filename,
  1345.                      FALSE, TRUE);
  1346.       script->arg_values[i].sfa_file.fileselection = sf_interface->args_widgets[i];
  1347.  
  1348.       gtk_signal_connect (GTK_OBJECT (sf_interface->args_widgets[i]),
  1349.                   "filename_changed",
  1350.                   (GtkSignalFunc) script_fu_file_selection_callback,
  1351.                   &script->arg_values[i].sfa_file);
  1352.       break;
  1353.  
  1354.     case SF_FONT:
  1355.       widget_leftalign = FALSE;
  1356.  
  1357.       sf_interface->args_widgets[i] = gtk_button_new ();
  1358.       script->arg_values[i].sfa_font.preview = gtk_label_new ("");
  1359.       script->arg_values[i].sfa_font.dialog = NULL;
  1360.       gtk_widget_set_usize (sf_interface->args_widgets[i], FONT_PREVIEW_WIDTH, 0);
  1361.       gtk_container_add (GTK_CONTAINER (sf_interface->args_widgets[i]),
  1362.                  script->arg_values[i].sfa_font.preview);
  1363.       gtk_widget_show (script->arg_values[i].sfa_font.preview);
  1364.  
  1365.       script_fu_font_preview (script->arg_values[i].sfa_font.preview,
  1366.                   script->arg_values[i].sfa_font.fontname);
  1367.  
  1368.       gtk_signal_connect (GTK_OBJECT (sf_interface->args_widgets[i]), "clicked",
  1369.                   (GtkSignalFunc) script_fu_font_preview_callback,
  1370.                   &script->arg_values[i].sfa_font);      
  1371.       break;
  1372.  
  1373.     case SF_PATTERN:
  1374.       sf_interface->args_widgets[i] =
  1375.         gimp_pattern_select_widget(_("Script-fu Pattern Selection"),
  1376.                        script->arg_values[i].sfa_pattern, 
  1377.                        script_fu_pattern_preview,
  1378.                        &script->arg_values[i].sfa_pattern);
  1379.       break;
  1380.     case SF_GRADIENT:
  1381.       sf_interface->args_widgets[i] =
  1382.         gimp_gradient_select_widget(_("Script-Fu Gradient Selection"),
  1383.                     script->arg_values[i].sfa_gradient, 
  1384.                     script_fu_gradient_preview,
  1385.                     &script->arg_values[i].sfa_gradient);
  1386.       break;
  1387.  
  1388.     case SF_BRUSH:
  1389.       sf_interface->args_widgets[i] = 
  1390.         gimp_brush_select_widget(_("Script-Fu Brush Selection"),
  1391.                      script->arg_values[i].sfa_brush.name, 
  1392.                      script->arg_values[i].sfa_brush.opacity, 
  1393.                      script->arg_values[i].sfa_brush.spacing, 
  1394.                      script->arg_values[i].sfa_brush.paint_mode, 
  1395.                      script_fu_brush_preview,
  1396.                      &script->arg_values[i].sfa_brush);
  1397.       break;
  1398.  
  1399.     case SF_OPTION:
  1400.       sf_interface->args_widgets[i] = gtk_option_menu_new ();
  1401.       menu = gtk_menu_new ();
  1402.       for (list = script->arg_defaults[i].sfa_option.list, j = 0; 
  1403.            list; 
  1404.            list = g_slist_next (list), j++)
  1405.         {
  1406.           menu_item = gtk_menu_item_new_with_label (gettext ((gchar *)list->data));
  1407.           gtk_object_set_user_data (GTK_OBJECT (menu_item), 
  1408.                     GUINT_TO_POINTER (j));
  1409.           gtk_menu_append (GTK_MENU (menu), menu_item);
  1410.           gtk_widget_show (menu_item);
  1411.         }
  1412.       gtk_option_menu_set_menu (GTK_OPTION_MENU (sf_interface->args_widgets[i]),
  1413.                     menu);
  1414.       gtk_option_menu_set_history (GTK_OPTION_MENU (sf_interface->args_widgets[i]), 
  1415.                             script->arg_values[i].sfa_option.history);
  1416.       break;
  1417.       
  1418.     default:
  1419.       break;
  1420.     }
  1421.  
  1422.       gimp_table_attach_aligned (GTK_TABLE (table), 0, i,
  1423.                  label_text, 1.0, label_yalign,
  1424.                  sf_interface->args_widgets[i], 1, 
  1425.                  widget_leftalign);
  1426.       g_free (label_text);
  1427.     }
  1428.  
  1429.   gtk_widget_show (table);
  1430.  
  1431.   /*  Reset to defaults */
  1432.   hbox = gtk_hbox_new (FALSE, 0);
  1433.   gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 0);
  1434.   gtk_container_set_border_width (GTK_CONTAINER (hbox), 4);
  1435.  
  1436.   button = gtk_button_new_with_label (_("Reset to Defaults"));
  1437.   gtk_misc_set_padding (GTK_MISC (GTK_BIN (button)->child), 2, 0);
  1438.   gtk_signal_connect (GTK_OBJECT (button), "clicked",
  1439.                       (GtkSignalFunc) script_fu_reset_callback,
  1440.               script);
  1441.   gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0);
  1442.   gtk_widget_show (button);
  1443.   gtk_widget_show (hbox);
  1444.  
  1445.   gtk_widget_show (vbox);
  1446.   gtk_widget_show (frame);
  1447.  
  1448.   /*  Separator  */
  1449.   sep = gtk_hseparator_new ();
  1450.   gtk_box_pack_start (GTK_BOX (main_box), sep, FALSE, FALSE, 0);
  1451.   gtk_widget_show (sep);
  1452.  
  1453.   /*  Action area  */
  1454.   hbox = gtk_hbox_new (FALSE, 0);
  1455.   gtk_container_set_border_width (GTK_CONTAINER (hbox), 2);
  1456.   gtk_box_pack_start (GTK_BOX (main_box), hbox, FALSE, TRUE, 0);
  1457.  
  1458.   bbox = gtk_hbutton_box_new ();
  1459.   gtk_button_box_set_spacing (GTK_BUTTON_BOX (bbox), 4);
  1460.   gtk_box_pack_start (GTK_BOX (hbox), bbox, FALSE, FALSE, 0);
  1461.  
  1462.   button = gtk_button_new_with_label (_("About"));
  1463.   GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
  1464.   gtk_signal_connect (GTK_OBJECT (button), "clicked",
  1465.                       GTK_SIGNAL_FUNC (script_fu_about_callback),
  1466.                       script);
  1467.   gtk_container_add (GTK_CONTAINER (bbox), button);  
  1468.   gtk_widget_show (button);
  1469.  
  1470.   gtk_widget_show (bbox);
  1471.  
  1472.   bbox = gtk_hbutton_box_new ();
  1473.   gtk_button_box_set_spacing (GTK_BUTTON_BOX (bbox), 4);
  1474.   gtk_box_pack_end (GTK_BOX (hbox), bbox, FALSE, FALSE, 0);
  1475.  
  1476.   button = gtk_button_new_with_label (_("OK"));
  1477.   GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
  1478.   gtk_signal_connect (GTK_OBJECT (button), "clicked",
  1479.               GTK_SIGNAL_FUNC (script_fu_ok_callback),
  1480.               script);
  1481.   gtk_container_add (GTK_CONTAINER (bbox), button);  
  1482.   gtk_widget_grab_default (button);
  1483.   gtk_widget_show (button);
  1484.  
  1485.   button = gtk_button_new_with_label (_("Cancel"));
  1486.   GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
  1487.   gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
  1488.                  GTK_SIGNAL_FUNC (script_fu_interface_quit),
  1489.                  (GtkObject *) script);
  1490.   gtk_container_add (GTK_CONTAINER (bbox), button);  
  1491.   gtk_widget_show (button);
  1492.  
  1493.   gtk_widget_show (bbox);
  1494.   gtk_widget_show (hbox);
  1495.  
  1496.   /* The statusbar (well it's a faked statusbar...) */
  1497.   hbox = gtk_hbox_new (FALSE, 0);
  1498.   gtk_box_pack_start (GTK_BOX (main_box), hbox, FALSE, FALSE, 2);
  1499.   gtk_widget_show (hbox);
  1500.  
  1501.   sf_interface->status = gtk_entry_new ();
  1502.   gtk_entry_set_editable (GTK_ENTRY (sf_interface->status), FALSE);
  1503.   gtk_box_pack_start (GTK_BOX (hbox), sf_interface->status, TRUE, TRUE, 2);
  1504.   gtk_entry_set_text (GTK_ENTRY (sf_interface->status), 
  1505.               sf_interface->window_title);
  1506.   gtk_widget_show (sf_interface->status);
  1507.  
  1508.   gtk_widget_show (main_box);
  1509.   gtk_widget_show (dlg);
  1510.  
  1511.   gtk_main ();
  1512. }
  1513.  
  1514. static void
  1515. script_fu_interface_quit (SFScript *script)
  1516. {
  1517.   gint i;
  1518.  
  1519.   g_return_if_fail (script != NULL);
  1520.   g_return_if_fail (sf_interface != NULL);  
  1521.  
  1522.   g_free (sf_interface->window_title);
  1523.  
  1524.   if (sf_interface->about_dialog)
  1525.     gtk_widget_destroy (sf_interface->about_dialog);
  1526.  
  1527.   for (i = 0; i < script->num_args; i++)
  1528.     switch (script->arg_types[i])
  1529.       {
  1530.       case SF_FONT:
  1531.     if (script->arg_values[i].sfa_font.dialog != NULL)
  1532.       {
  1533.         gtk_widget_destroy (script->arg_values[i].sfa_font.dialog);
  1534.         script->arg_values[i].sfa_font.dialog = NULL;
  1535.       }
  1536.     break;
  1537.  
  1538.       case SF_PATTERN:
  1539.       gimp_pattern_select_widget_close_popup (sf_interface->args_widgets[i]); 
  1540.     break;
  1541.  
  1542.       case SF_GRADIENT:
  1543.       gimp_gradient_select_widget_close_popup (sf_interface->args_widgets[i]); 
  1544.     break;
  1545.  
  1546.       case SF_BRUSH:
  1547.       gimp_brush_select_widget_close_popup (sf_interface->args_widgets[i]); 
  1548.     break;
  1549.  
  1550.       default:
  1551.     break;
  1552.       }
  1553.  
  1554.   g_free (sf_interface->args_widgets);
  1555.   g_free (sf_interface->last_command);
  1556.  
  1557.   g_free (sf_interface);
  1558.   sf_interface = NULL;
  1559.  
  1560.   /*  
  1561.    *  We do not call gtk_main_quit() earlier to reduce the possibility
  1562.    *  that script_fu_script_proc() is called from gimp_extension_process()
  1563.    *  while we are not finished with the current script. This sucks!
  1564.    */
  1565.  
  1566.   gtk_main_quit ();
  1567. }
  1568.  
  1569. static void
  1570. script_fu_pattern_preview (gchar    *name,
  1571.                gint      width,
  1572.                gint      height,
  1573.                gint      bytes,
  1574.                gchar    *mask_data,
  1575.                gint      closing,
  1576.                gpointer  data)
  1577. {
  1578.   gchar **pname;
  1579.  
  1580.   pname = (gchar **) data;
  1581.  
  1582.   g_free (*pname);
  1583.   *pname = g_strdup (name);
  1584. }
  1585.  
  1586. static void
  1587. script_fu_gradient_preview (gchar    *name,
  1588.                 gint      width,
  1589.                 gdouble  *mask_data,
  1590.                 gint      closing,
  1591.                 gpointer  data)
  1592. {
  1593.   gchar **gname;
  1594.  
  1595.   gname = (gchar **) data;
  1596.  
  1597.   g_free (*gname);
  1598.   *gname = g_strdup (name);
  1599. }
  1600.  
  1601. static void      
  1602. script_fu_brush_preview (gchar    *name,
  1603.              gdouble   opacity,
  1604.              gint      spacing,
  1605.              gint      paint_mode,
  1606.              gint      width,
  1607.              gint      height,
  1608.              gchar    *mask_data,
  1609.              gint      closing,
  1610.              gpointer  data)
  1611. {
  1612.   SFBrush *brush;
  1613.  
  1614.   brush = (SFBrush *) data;
  1615.  
  1616.   g_free (brush->name);
  1617.   brush->name       = g_strdup (name);
  1618.   brush->opacity    = opacity;
  1619.   brush->spacing    = spacing;
  1620.   brush->paint_mode = paint_mode;
  1621. }
  1622.  
  1623. static void
  1624. script_fu_font_preview (GtkWidget *preview,
  1625.             gchar     *data)
  1626. {
  1627.   GdkFont *font;
  1628.   gchar *fontname;
  1629.   gchar *family;
  1630.  
  1631.   if (data == NULL) 
  1632.     return;
  1633.  
  1634.   fontname = g_strdup (data);
  1635.  
  1636.   /* Check if the fontname is valid and the font is present */
  1637.   font = gdk_font_load (fontname);
  1638.  
  1639.   if (font != NULL)
  1640.     {
  1641.       gdk_font_unref (font);
  1642.  
  1643.       strtok (fontname, "-");
  1644.       family = strtok (NULL, "-");
  1645.       g_strup (family);
  1646.  
  1647.       gtk_label_set_text (GTK_LABEL (preview), family);
  1648.     }
  1649.   else
  1650.     {
  1651.       gtk_label_set_text (GTK_LABEL (preview), _("NOT SET"));
  1652.     }
  1653.   
  1654.   g_free (fontname);
  1655. }
  1656.  
  1657. static void
  1658. script_fu_ok_callback (GtkWidget *widget,
  1659.                gpointer   data)
  1660. {
  1661.   GdkFont   *font;
  1662.   GtkWidget *menu_item;
  1663.   gchar     *escaped;
  1664.   gchar     *text = NULL;
  1665.   gchar     *command;
  1666.   gchar     *c;
  1667.   gchar      buffer[MAX_STRING_LENGTH];
  1668.   gint       length;
  1669.   gint       i;
  1670.  
  1671.   SFScript  *script = (SFScript *) data;
  1672.   
  1673.   /* Check if choosen fonts are there */
  1674.   for (i = 0; i < script->num_args; i++)
  1675.     if (script->arg_types[i] == SF_FONT)
  1676.       {
  1677.     font = gdk_font_load (script->arg_values[i].sfa_font.fontname);
  1678.     if (font == NULL)
  1679.       {
  1680.         g_message (_("At least one font you've choosen is invalid.\n"
  1681.              "Please check your settings.\n"));
  1682.         return;
  1683.       }
  1684.     else
  1685.       gdk_font_unref (font);
  1686.       }
  1687.   
  1688.   length = strlen (script->script_name) + 3;
  1689.  
  1690.   for (i = 0; i < script->num_args; i++)
  1691.     switch (script->arg_types[i])
  1692.       {
  1693.       case SF_IMAGE:
  1694.       case SF_DRAWABLE:
  1695.       case SF_LAYER:
  1696.       case SF_CHANNEL:
  1697.     length += 12;  /*  Maximum size of integer value will not exceed this many characters  */
  1698.     break;
  1699.  
  1700.       case SF_COLOR:
  1701.     length += 16;  /*  Maximum size of color string: '(XXX XXX XXX)  */
  1702.     break;
  1703.  
  1704.       case SF_TOGGLE:
  1705.     length += 6;   /*  Maximum size of (TRUE, FALSE)  */
  1706.     break;
  1707.  
  1708.       case SF_VALUE:
  1709.     length += strlen (gtk_entry_get_text (GTK_ENTRY (sf_interface->args_widgets[i]))) + 1;
  1710.     break;
  1711.  
  1712.       case SF_STRING:
  1713.     escaped = ESCAPE (gtk_entry_get_text (GTK_ENTRY (sf_interface->args_widgets[i])));
  1714.     length += strlen (escaped) + 3;
  1715.     g_free (escaped);
  1716.     break;
  1717.  
  1718.       case SF_ADJUSTMENT:
  1719.     length += 24;  /*  Maximum size of float value should not exceed this many characters  */
  1720.     break;
  1721.  
  1722.       case SF_FILENAME:
  1723.     escaped = ESCAPE (script->arg_values[i].sfa_file.filename);
  1724.     length += strlen (escaped) + 3;
  1725.     g_free (escaped);
  1726.     break;
  1727.  
  1728.       case SF_FONT:
  1729.     length += strlen (script->arg_values[i].sfa_font.fontname) + 3;
  1730.     break;
  1731.  
  1732.       case SF_PATTERN:
  1733.     length += strlen (script->arg_values[i].sfa_pattern) + 3;
  1734.     break;
  1735.  
  1736.       case SF_GRADIENT:
  1737.     length += strlen (script->arg_values[i].sfa_gradient) + 3;
  1738.     break;
  1739.  
  1740.       case SF_BRUSH:
  1741.     length += strlen (script->arg_values[i].sfa_brush.name) + 3;
  1742.     length += 36; /* Maximum size of three ints for opacity, spacing,mode*/
  1743.     break;
  1744.  
  1745.       case SF_OPTION:
  1746.     length += 12;  /*  Maximum size of integer value will not exceed this many characters  */
  1747.     break;
  1748.  
  1749.       default:
  1750.     break;
  1751.       }
  1752.  
  1753.   c = command = g_new (gchar, length);
  1754.  
  1755.   sprintf (command, "(%s ", script->script_name);
  1756.   c += strlen (script->script_name) + 2;
  1757.   for (i = 0; i < script->num_args; i++)
  1758.     {
  1759.       switch (script->arg_types[i])
  1760.     {
  1761.     case SF_IMAGE:
  1762.     case SF_DRAWABLE:
  1763.     case SF_LAYER:
  1764.     case SF_CHANNEL:
  1765.       g_snprintf (buffer, sizeof (buffer), "%d",
  1766.               script->arg_values[i].sfa_image);
  1767.       text = buffer;
  1768.       break;
  1769.  
  1770.      case SF_COLOR:
  1771.       g_snprintf (buffer, sizeof (buffer), "'(%d %d %d)",
  1772.               script->arg_values[i].sfa_color[0],
  1773.               script->arg_values[i].sfa_color[1],
  1774.               script->arg_values[i].sfa_color[2]);
  1775.       text = buffer;
  1776.       break;
  1777.  
  1778.     case SF_TOGGLE:
  1779.       g_snprintf (buffer, sizeof (buffer), "%s",
  1780.               (script->arg_values[i].sfa_toggle) ? "TRUE" : "FALSE");
  1781.       text = buffer;
  1782.       break;
  1783.  
  1784.     case SF_VALUE:
  1785.       text = gtk_entry_get_text (GTK_ENTRY (sf_interface->args_widgets[i]));
  1786.       g_free (script->arg_values[i].sfa_value);
  1787.       script->arg_values[i].sfa_value = g_strdup (text); 
  1788.       break;
  1789.  
  1790.     case SF_STRING:
  1791.       text = gtk_entry_get_text (GTK_ENTRY (sf_interface->args_widgets[i]));
  1792.       g_free (script->arg_values[i].sfa_value);
  1793.       script->arg_values[i].sfa_value = g_strdup (text); 
  1794.       escaped = ESCAPE (text);
  1795.       g_snprintf (buffer, sizeof (buffer), "\"%s\"", escaped);
  1796.       g_free (escaped);
  1797.       text = buffer;
  1798.       break;
  1799.  
  1800.     case SF_ADJUSTMENT:
  1801.       switch (script->arg_defaults[i].sfa_adjustment.type)
  1802.         {
  1803.         case SF_SLIDER:
  1804.           script->arg_values[i].sfa_adjustment.value =
  1805.         script->arg_values[i].sfa_adjustment.adj->value;
  1806.           g_snprintf (buffer, sizeof (buffer), "%f",
  1807.               script->arg_values[i].sfa_adjustment.value);
  1808.           text = buffer;
  1809.           break;
  1810.  
  1811.         case SF_SPINNER:
  1812.           script->arg_values[i].sfa_adjustment.value = 
  1813.         gtk_spin_button_get_value_as_float (GTK_SPIN_BUTTON (sf_interface->args_widgets[i]));
  1814.           g_snprintf (buffer, sizeof (buffer), "%f",
  1815.               script->arg_values[i].sfa_adjustment.value);
  1816.           text = buffer;
  1817.           break;
  1818.  
  1819.         default:
  1820.           break;
  1821.         }
  1822.       break;
  1823.  
  1824.     case SF_FILENAME:
  1825.       escaped = ESCAPE (script->arg_values[i].sfa_file.filename);
  1826.       g_snprintf (buffer, sizeof (buffer), "\"%s\"", escaped);
  1827.       g_free (escaped);
  1828.       text = buffer;
  1829.       break;
  1830.  
  1831.     case SF_FONT:
  1832.       g_snprintf (buffer, sizeof (buffer), "\"%s\"",
  1833.               script->arg_values[i].sfa_font.fontname);
  1834.       text = buffer;
  1835.       break;
  1836.  
  1837.     case SF_PATTERN:
  1838.       g_snprintf (buffer, sizeof (buffer), "\"%s\"",
  1839.               script->arg_values[i].sfa_pattern);
  1840.       text = buffer;
  1841.       break;
  1842.  
  1843.     case SF_GRADIENT:
  1844.       g_snprintf (buffer, sizeof (buffer), "\"%s\"",
  1845.               script->arg_values[i].sfa_gradient);
  1846.       text = buffer;
  1847.       break;
  1848.  
  1849.     case SF_BRUSH:
  1850.       g_snprintf (buffer, sizeof (buffer), "'(\"%s\" %f %d %d)",
  1851.               script->arg_values[i].sfa_brush.name,
  1852.               script->arg_values[i].sfa_brush.opacity,
  1853.               script->arg_values[i].sfa_brush.spacing,
  1854.               script->arg_values[i].sfa_brush.paint_mode);
  1855.       text = buffer;
  1856.       break;
  1857.  
  1858.     case SF_OPTION:
  1859.       menu_item = 
  1860.         gtk_menu_get_active (GTK_MENU (gtk_option_menu_get_menu (GTK_OPTION_MENU (sf_interface->args_widgets[i]))));
  1861.       script->arg_values[i].sfa_option.history = 
  1862.         GPOINTER_TO_UINT (gtk_object_get_user_data (GTK_OBJECT (menu_item))); 
  1863.       g_snprintf (buffer, sizeof (buffer), "%d",
  1864.               script->arg_values[i].sfa_option.history);
  1865.       text = buffer;
  1866.       break;
  1867.  
  1868.     default:
  1869.       break;
  1870.     }
  1871.  
  1872.       if (i == script->num_args - 1)
  1873.     sprintf (c, "%s)", text);
  1874.       else
  1875.     sprintf (c, "%s ", text);
  1876.       c += strlen (text) + 1;
  1877.     }
  1878.  
  1879.   /*  run the command through the interpreter  */
  1880.   if (repl_c_string (command, 0, 0, 1) != 0)
  1881.     script_fu_error_msg (command);
  1882.  
  1883.   g_free (command);
  1884.  
  1885.   script_fu_interface_quit (script);
  1886. }
  1887.  
  1888. static void
  1889. script_fu_about_callback (GtkWidget *widget,
  1890.               gpointer   data)
  1891. {
  1892.   GtkWidget *dialog;
  1893.   GtkWidget *frame;
  1894.   GtkWidget *vbox;
  1895.   GtkWidget *hbox;
  1896.   GtkWidget *button;
  1897.   GtkWidget *label;
  1898.   GtkWidget *table;
  1899.   GtkWidget *text;
  1900.   GtkWidget *vscrollbar;
  1901.  
  1902.   SFScript  *script = (SFScript *) data;
  1903.  
  1904.   if (sf_interface->about_dialog == NULL)
  1905.     {
  1906.       dialog = gtk_dialog_new ();
  1907.       gtk_window_set_title (GTK_WINDOW (dialog), sf_interface->window_title);
  1908.       gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_MOUSE);
  1909.       gtk_signal_connect_object (GTK_OBJECT (dialog), "delete_event",
  1910.                  GTK_SIGNAL_FUNC (gtk_widget_destroy),
  1911.                  GTK_OBJECT (dialog));
  1912.  
  1913.       gimp_help_connect_help_accel (dialog, gimp_standard_help_func,
  1914.                     "filters/script-fu.html");
  1915.   
  1916.       frame = gtk_frame_new (NULL);
  1917.       gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
  1918.       gtk_container_set_border_width (GTK_CONTAINER (frame), 2);
  1919.       gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), frame,
  1920.               TRUE, TRUE, 0);
  1921.       gtk_widget_show (frame);
  1922.       
  1923.       vbox = gtk_vbox_new (FALSE, 2);
  1924.       gtk_container_add (GTK_CONTAINER (frame), vbox);
  1925.       gtk_container_set_border_width (GTK_CONTAINER (vbox), 2);
  1926.       gtk_widget_show (vbox);
  1927.  
  1928.       /* the name */
  1929.       hbox = gtk_hbox_new (FALSE, 2);
  1930.       gtk_container_set_border_width (GTK_CONTAINER (hbox), 2);
  1931.       gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
  1932.       gtk_widget_show (hbox);
  1933.       
  1934.       label = gtk_label_new (script->script_name);
  1935.       gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 0);
  1936.       gtk_widget_show (label);
  1937.  
  1938.       /* the help display */
  1939.       table = gtk_table_new (2, 2, FALSE);
  1940.       gtk_table_set_row_spacing (GTK_TABLE (table), 0, 2);
  1941.       gtk_table_set_col_spacing (GTK_TABLE (table), 0, 2);
  1942.       gtk_box_pack_start (GTK_BOX (vbox), table, TRUE, TRUE, 0);
  1943.       gtk_widget_show (table);
  1944.  
  1945.       text = gtk_text_new (NULL, NULL);
  1946.       gtk_text_set_editable (GTK_TEXT (text), FALSE);
  1947.       gtk_text_set_word_wrap (GTK_TEXT (text), TRUE);      
  1948.       gtk_table_attach (GTK_TABLE (table), text, 0, 1, 0, 1,
  1949.             GTK_EXPAND | GTK_SHRINK | GTK_FILL,
  1950.             GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0);
  1951.       gtk_widget_set_usize (text, 200, 60);
  1952.       gtk_widget_show (text);
  1953.  
  1954.       vscrollbar = gtk_vscrollbar_new (GTK_TEXT (text)->vadj);
  1955.       gtk_table_attach (GTK_TABLE (table), vscrollbar, 1, 2, 0, 1,
  1956.             GTK_FILL, GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0);
  1957.       gtk_widget_show (vscrollbar);
  1958.  
  1959.       gtk_widget_realize (text);
  1960.       gtk_text_freeze (GTK_TEXT (text));
  1961.       gtk_text_insert (GTK_TEXT (text), NULL, &text->style->black, NULL,
  1962.                script->help, -1);
  1963.    
  1964.       /* author, copyright, etc. */
  1965.       table = gtk_table_new (2, 4, FALSE);
  1966.       gtk_table_set_col_spacings (GTK_TABLE (table), 4);
  1967.       gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0);
  1968.       gtk_widget_show (table);
  1969.  
  1970.       label = gtk_label_new (script->author);
  1971.       gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
  1972.       gimp_table_attach_aligned (GTK_TABLE (table), 0, 0,
  1973.                  _("Author:"), 1.0, 0.5,
  1974.                  label, 1, FALSE);
  1975.  
  1976.       label = gtk_label_new (script->copyright);
  1977.       gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); 
  1978.       gimp_table_attach_aligned (GTK_TABLE (table), 0, 1,
  1979.                  _("Copyright:"), 1.0, 0.5,
  1980.                  label, 1, FALSE);
  1981.  
  1982.       label = gtk_label_new (script->date);
  1983.       gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); 
  1984.       gimp_table_attach_aligned (GTK_TABLE (table), 0, 2,
  1985.                  _("Date:"), 1.0, 0.5,
  1986.                  label, 1, FALSE);
  1987.  
  1988.       if (strlen (script->img_types) > 0)
  1989.     {
  1990.       label = gtk_label_new (script->img_types);
  1991.       gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); 
  1992.       gimp_table_attach_aligned (GTK_TABLE (table), 0, 3,
  1993.                      _("Image Types:"), 1.0, 0.5,
  1994.                      label, 1, FALSE);
  1995.     }
  1996.  
  1997.       gtk_widget_show (frame);
  1998.       gtk_text_thaw (GTK_TEXT (text));
  1999.  
  2000.       /*  action area  */
  2001.       gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (dialog)->action_area), 2);
  2002.       button = gtk_button_new_with_label (_("Close"));
  2003.       GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
  2004.       gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
  2005.                  GTK_SIGNAL_FUNC (gtk_widget_destroy),
  2006.                  GTK_OBJECT (dialog));
  2007.       gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->action_area), 
  2008.               button, TRUE, TRUE, 0);
  2009.       gtk_widget_grab_default (button);
  2010.       gtk_widget_show (button);
  2011.  
  2012.       sf_interface->about_dialog = dialog;
  2013.  
  2014.       gtk_signal_connect (GTK_OBJECT (dialog), "destroy",
  2015.               GTK_SIGNAL_FUNC (gtk_widget_destroyed),
  2016.               &sf_interface->about_dialog);
  2017.     }
  2018.  
  2019.   gtk_window_set_position (GTK_WINDOW (sf_interface->about_dialog),
  2020.                GTK_WIN_POS_MOUSE);  
  2021.   gtk_widget_show (sf_interface->about_dialog);
  2022. }
  2023.  
  2024. static void
  2025. script_fu_reset_callback (GtkWidget *widget,
  2026.               gpointer   data)
  2027. {
  2028.   gint i, j;
  2029.  
  2030.   SFScript *script = (SFScript *) data;
  2031.  
  2032.   for (i = 0; i < script->num_args; i++)
  2033.     switch (script->arg_types[i])
  2034.       {
  2035.       case SF_IMAGE:
  2036.       case SF_DRAWABLE:
  2037.       case SF_LAYER:
  2038.       case SF_CHANNEL:
  2039.     break;
  2040.  
  2041.       case SF_COLOR:
  2042.     for (j = 0; j < 3; j++)
  2043.       {
  2044.         script->arg_values[i].sfa_color[j] = 
  2045.           script->arg_defaults[i].sfa_color[j];
  2046.       }
  2047.     gimp_color_button_update (GIMP_COLOR_BUTTON (sf_interface->args_widgets[i]));
  2048.     break;
  2049.  
  2050.       case SF_TOGGLE:
  2051.     script->arg_values[i].sfa_toggle = script->arg_defaults[i].sfa_toggle;
  2052.     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (sf_interface->args_widgets[i]),
  2053.                       script->arg_values[i].sfa_toggle);
  2054.     break;
  2055.  
  2056.       case SF_VALUE:
  2057.       case SF_STRING:
  2058.     g_free (script->arg_values[i].sfa_value);
  2059.     script->arg_values[i].sfa_value =
  2060.       g_strdup (script->arg_defaults[i].sfa_value); 
  2061.     gtk_entry_set_text (GTK_ENTRY (sf_interface->args_widgets[i]), 
  2062.                 script->arg_values[i].sfa_value);
  2063.     break;
  2064.  
  2065.       case SF_ADJUSTMENT:
  2066.     script->arg_values[i].sfa_adjustment.value =
  2067.       script->arg_defaults[i].sfa_adjustment.value;
  2068.     gtk_adjustment_set_value (script->arg_values[i].sfa_adjustment.adj, 
  2069.                   script->arg_values[i].sfa_adjustment.value);
  2070.     break;
  2071.  
  2072.       case SF_FILENAME:
  2073.     g_free (script->arg_values[i].sfa_file.filename);
  2074.     script->arg_values[i].sfa_file.filename =
  2075.       g_strdup (script->arg_defaults[i].sfa_file.filename);
  2076.     gimp_file_selection_set_filename
  2077.       (GIMP_FILE_SELECTION (script->arg_values[i].sfa_file.fileselection),
  2078.        script->arg_values[i].sfa_file.filename);
  2079.     break;
  2080.  
  2081.       case SF_FONT:
  2082.     g_free (script->arg_values[i].sfa_font.fontname);
  2083.     script->arg_values[i].sfa_font.fontname =
  2084.       g_strdup (script->arg_defaults[i].sfa_font.fontname);
  2085.     if (script->arg_values[i].sfa_font.dialog)
  2086.       {
  2087.         gtk_font_selection_dialog_set_font_name
  2088.           (GTK_FONT_SELECTION_DIALOG (script->arg_values[i].sfa_font.dialog),
  2089.            script->arg_values[i].sfa_font.fontname);
  2090.       }    
  2091.     script_fu_font_preview (script->arg_values[i].sfa_font.preview,
  2092.                 script->arg_values[i].sfa_font.fontname);
  2093.     break;
  2094.  
  2095.       case SF_PATTERN:
  2096.       gimp_pattern_select_widget_set_popup
  2097.       (sf_interface->args_widgets[i], script->arg_defaults[i].sfa_pattern);  
  2098.     break;
  2099.  
  2100.       case SF_GRADIENT:
  2101.       gimp_gradient_select_widget_set_popup
  2102.       (sf_interface->args_widgets[i], script->arg_defaults[i].sfa_gradient);  
  2103.     break;
  2104.  
  2105.       case SF_BRUSH:
  2106.       gimp_brush_select_widget_set_popup
  2107.       (sf_interface->args_widgets[i],
  2108.        script->arg_defaults[i].sfa_brush.name,
  2109.        script->arg_defaults[i].sfa_brush.opacity, 
  2110.        script->arg_defaults[i].sfa_brush.spacing, 
  2111.        script->arg_defaults[i].sfa_brush.paint_mode);  
  2112.     break;
  2113.  
  2114.       case SF_OPTION:
  2115.     script->arg_values[i].sfa_option.history = 
  2116.       script->arg_defaults[i].sfa_option.history;
  2117.     gtk_option_menu_set_history (GTK_OPTION_MENU (sf_interface->args_widgets[i]), 
  2118.                      script->arg_values[i].sfa_option.history);
  2119.  
  2120.       default:
  2121.     break;
  2122.       }
  2123. }
  2124.  
  2125. static void
  2126. script_fu_menu_callback  (gint32   id,
  2127.               gpointer data)
  2128. {
  2129.   *((gint32 *) data) = id;
  2130. }
  2131.  
  2132. static void
  2133. script_fu_file_selection_callback (GtkWidget *widget,
  2134.                    gpointer   data)
  2135. {
  2136.   SFFilename *file;
  2137.  
  2138.   file = (SFFilename *) data;
  2139.  
  2140.   if (file->filename)
  2141.     g_free (file->filename);
  2142.  
  2143.   file->filename = 
  2144.     gimp_file_selection_get_filename (GIMP_FILE_SELECTION (file->fileselection));
  2145. }
  2146.  
  2147. static void
  2148. script_fu_font_preview_callback (GtkWidget *widget,
  2149.                  gpointer   data)
  2150. {
  2151.   GtkFontSelectionDialog *fsd;
  2152.   SFFont *font;
  2153.  
  2154.   font = (SFFont *) data;
  2155.  
  2156.   if (!font->dialog)
  2157.     {
  2158.       font->dialog = gtk_font_selection_dialog_new (_("Script-Fu Font Selection"));
  2159.       fsd = GTK_FONT_SELECTION_DIALOG (font->dialog);
  2160.  
  2161.       gtk_signal_connect (GTK_OBJECT (fsd->ok_button), "clicked",
  2162.               GTK_SIGNAL_FUNC (script_fu_font_dialog_ok),
  2163.               font);
  2164.       gtk_signal_connect (GTK_OBJECT (fsd), "delete_event",
  2165.               GTK_SIGNAL_FUNC (script_fu_font_dialog_delete),
  2166.               font);
  2167.       gtk_signal_connect (GTK_OBJECT (fsd), "destroy",
  2168.               GTK_SIGNAL_FUNC (gtk_widget_destroyed),
  2169.               &font->dialog);
  2170.       gtk_signal_connect (GTK_OBJECT (fsd->cancel_button), "clicked",
  2171.               GTK_SIGNAL_FUNC (script_fu_font_dialog_cancel),
  2172.               font);
  2173.     }
  2174.   else
  2175.     fsd = GTK_FONT_SELECTION_DIALOG (font->dialog);
  2176.  
  2177.   gtk_font_selection_dialog_set_font_name (fsd, font->fontname);
  2178.   gtk_window_set_position (GTK_WINDOW (font->dialog), GTK_WIN_POS_MOUSE);
  2179.   gtk_widget_show (font->dialog);
  2180. }
  2181.  
  2182. static void
  2183. script_fu_font_dialog_ok (GtkWidget *widget,
  2184.               gpointer   data)
  2185. {
  2186.   SFFont *font;
  2187.   gchar  *fontname;
  2188.  
  2189.   font = (SFFont *) data;
  2190.  
  2191.   fontname = gtk_font_selection_dialog_get_font_name (GTK_FONT_SELECTION_DIALOG (font->dialog));
  2192.   if (fontname != NULL)
  2193.     {
  2194.       g_free (font->fontname);
  2195.       font->fontname = fontname;
  2196.     }
  2197.   gtk_widget_hide (font->dialog);
  2198.  
  2199.   script_fu_font_preview (font->preview, font->fontname);
  2200. }
  2201.  
  2202. static void
  2203. script_fu_font_dialog_cancel (GtkWidget *widget,
  2204.                   gpointer   data)
  2205. {
  2206.   SFFont *font;
  2207.  
  2208.   font = (SFFont *) data;
  2209.  
  2210.   gtk_widget_hide (font->dialog);
  2211. }
  2212.  
  2213. static gint
  2214. script_fu_font_dialog_delete (GtkWidget *widget,
  2215.                   GdkEvent  *event,
  2216.                   gpointer   data)
  2217. {
  2218.   script_fu_font_dialog_cancel (widget, data);
  2219.   return TRUE;
  2220. }
  2221.  
  2222. static void
  2223. script_fu_error_msg (gchar *command)
  2224. {
  2225.   g_message (_("Script-Fu Error while executing\n %s\n%s"), 
  2226.          command, siod_err_msg);
  2227. }
  2228.